#include "LogMessage.hpp"

#include <iostream>
#include <string>
#include <unordered_map>
#include <strings.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <arpa/inet.h>


const int BUFFER_SIZE = 128;

class UdpServer {
public:
  UdpServer(uint16_t port = 0, const std::string& ip = "", int sockfd = -1)
    :_ip(ip)
    ,_port(port)
    ,_sockfd(sockfd)
  {}
  void InitServer() {
    _sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if(_sockfd == -1) {
      LogMessage(FATAL, _F, _L, "create socket fail::%s", strerror(errno));
      exit(2);
    }

    // std::cout << "socket create success, sockfd::" << _sockfd << std::endl;
    sockaddr_in local;                  // 初始化的时候全部清零，可以用memset，也可以用bzero直接清零
    bzero(&local, sizeof(local));       // bzero会将local中的内容清零，这样local中的zero成员就不用管了
    local.sin_family = AF_INET;
    local.sin_port = htons(_port);
    local.sin_addr.s_addr = _ip == "" ? INADDR_ANY : inet_addr(_ip.c_str());

    if(bind(_sockfd, reinterpret_cast<const sockaddr*>(&local),sizeof(local)) < 0) {
      LogMessage(FATAL, _F, _L, "bind fail::%s", strerror(errno));
      exit(3);
    }

    LogMessage(NORMAL, _F, _L, "InitServer success");
  }

  void StartServer() {
    char buffer[BUFFER_SIZE];
    for(; ;) {
      // 1.接收数据
      sockaddr_in peer;
      socklen_t len = sizeof(peer);
      bzero(&peer, len);

      LogMessage(NORMAL, _F, _L, "recving...");
      
      ssize_t res = recvfrom(_sockfd, buffer, BUFFER_SIZE, 0, reinterpret_cast<sockaddr*>(&peer), &len);

      if(res > 0) {
        // 接收到数据了，最后一位要置为0
        buffer[res] = 0;

        // 2.分析和处理数据，这里让服务端执行客户端发来的命令
      }

      LogMessage(NORMAL, _F, _L, "receiv success");
      
      // client`s ip and port
      std::string client_ip = inet_ntoa(peer.sin_addr);
      uint16_t client_port = ntohs(peer.sin_port);
      // printf("[%s:%d]:%s\n", cli_IP.c_str(), cli_port, buffer);
      
      
      std::string sender;
      sender = "[" + client_ip + ":" + std::to_string(client_port) + "]";
      _clients.insert(std::make_pair(sender, peer));
  
      sender += "#";
      sender += buffer;
      std::cout << "sender::" << sender << std::endl;
      for(auto& client: _clients) {
        std::cout << client.first << std::endl; 
        // 0 note block
        sendto(_sockfd, sender.c_str(), sender.size(), 0, reinterpret_cast<sockaddr*>(&client.second), len);
      }
    }
  }

  ~UdpServer() {
    if(_sockfd >= 0) {
      close(_sockfd);
    }
  }
private:
  std::string _ip;  // server`s ip
  uint16_t _port;   // server`s port
  int _sockfd;
  std::unordered_map<std::string, struct sockaddr_in> _clients;
};




